Consider the problem of removing edges from a connected, weighted, undirected graph G to form a subgraph such that all the vertices remain connected and the sum of the weights on the remaining edges is as small as possible. Such a problem has numerous applications.
- Road construction: want to connect a set of cities with a minimum amount of road.
- Telecommunications: want to use a minimal length of cable.
- Plumbing: want to use a minimal amount of pipe.
A spanning tree for graph G is a connected subgraph that contains all the vertices in G and is a tree. An algorithm for our problem must obtain a spanning tree of minimum weight. Such a tree is called a minimum spanning tree
. A graph can have more than one minimum spanning tree.
A subgraph with minimum weight must be a tree, because if a subgraph were not a tree, it would contain a simple cycle
, and we could remove any edge on the cycle, resulting in a connected graph with a smaller weight. It is possible that a graph can have more than one minimum spanning tree.
그래프 G에 대한 신장트리는 G의 모든 정점을 포함한 트리이다. 하나의 그래프에는 여러 신장트리가 존재할 수 있는데, 모든 신장트리가 최소신장트리는 아니다. 이번 알고리즘의 목적은 여러 신장트리 중 가중치 합이 가장 작은 신장트리를 찾는 것이다.
최소의 가중치를 갖는 부분그래프는 반드시 트리이다. 그렇지 않으면 그래프 내에는 순환경로(cycle)가 있을 것이고, 그 순환경로상의 한 이음선을 제거함으로써 더 작은 비용의 신장트리를 만들 수 있다.
Example
Determine a minimum spanning tree.
Step 1
시작 정점으로 $v_1$을 선택한다.
Step 2
{$v_1$}에서 가장 가까운 정점인 $v_2$를 추가한다. 여기서 가깝다는 뜻은 이음선의 길이가 가장 작음을 의미한다.
Step 3
{$v_1$, $v_2$}에서 가장 가까운 정점인 $v_3$를 추가한다.
Step 4
{$v_1$, $v_2$, $v_3$}에서 가장 가까운 정점인 $v_5$를 추가한다.
Step 5
{$v_1$, $v_2$, $v_3$, $v_5$}에서 선택되지 않은 가장 작은 이음선의 값은 3이다. 하지만 이 값을 선택하면 순환경로가 생기므로 선택하지 않고, 그 다음 작은 값인 $v_3$과 $v_4$를 잇는 이음선을 선택하면서 마지막 정점인 $v_4$를 추가한다. 이렇게 모든 정점을 포함하게 되면 최소신장트리가 완성된다.
Prim’s Algorithm
Algorithm Design
Prim’s algorithm starts with an empty subset of edges F and a subset of vertices Y initialized to contain an arbitrary vertex. We will initialize Y to {$v_1$}. A vertex nearest to Y is a vertex in V - Y that is connected to a vertex in Y by an edge of minimum weight.
Because at the start Y = {$v_1$}, nearest[i] is initialized to 1 and distance[i] is initialized to the weight on the edge between $v_1$ and $v_i$. As vertices are added to Y, these two arrays are updated to reference the new vertex in Y nearest to each vertex outside of Y. To determine which vertex to add to Y, in each iteration we compute the index for which distance[i] is the smallest. We call this index vnear. The vertex indexed by vnear is added to Y by setting distance[vnear] to −1.
[용어정의]
구분 | 설명 |
---|---|
G=(V,E) | 모든 정점들의 집합 V와 모든 이음선들의 집합 E로 구성된 그래프이다. |
F | E의 유망한 부분집합이다(최소신장트리가 되도록 이음선 추가 가능) |
Y | F의 이음선들에 의해 연결된 정점들의 집합이다. |
nearest[i] | Y에 속한 정점 중에서 $v_i$와 가장 가까운 정점의 인덱스이다. |
distance[i] | $v_i$와 nearest[i]를 잇는 이음선의 가중치이다. |
vnear | Y에 추가 할 정점을 결정하기 위해 distance[i] 중 최소값을 보유한 인덱스를 찾는데, 이 인덱스를 vnear라고 부른다. |
[프림 알고리즘 초기화 로직]
distance[2]의 값은 W[1][2], distance[3]는 W[1][3], …, distance[k]는 W[1][k] 일 것이다. 왜냐하면 초기화 시점에서 Y에 속한 정점은 시작정점, 즉 $v_1$하나이므로 이를 통해서만 다른 정점으로 갈 수 있기 때문이다. nearest[i]는 시작정점인 $v_1$으로 값을 초기화한다. 즉, nearest[2], nearest[3], …, nearest[k] 모두 1로 초기화 된다. 시작정점을 제외한 다른 모든 정점들에게 가장 가까운 정점을 $v_1$으로 초기화 시키는 것 뿐이다. (해당 정점으로 갈 수 있는 이음선이 없을지라도)
[프림 알고리즘 메인 로직]
시작정점을 포함시키지 않아도 되므로 총 n-1번의 루프 수행과정에서 distance[i]와 nearest[i]값들을 갱신해 나가며 최소신장트리를 완성한다. distance[i]의 값들 중에서 가장 작은 이음선의 값을 찾아 기록한 후, 추가된 정점을 통해 갈 수 있는 이음선의 값이 기존의 값 보다 작다면 distance[i]와 nearest[i] 값을 갱신한다.
min | vnear | distance [2][3][4][5] |
nearest [2][3][4][5] |
|
---|---|---|---|---|
Step 1 | - | - | 1 3 ∞ ∞ | 1 1 1 1 |
Step 2 | 1 | 2 | -1 3 6 ∞ | 1 1 2 1 |
Step 3 | 3 | 3 | -1 -1 4 2 | 1 1 3 3 |
Step 4 | 2 | 5 | -1 -1 4 -1 | 1 1 3 3 |
Step 5 | 4 | 4 | -1 -1 -1 -1 | 1 1 3 3 |
이해를 돕기 위해 위의 예제의 $v_2$가 추가되는 과정(Step 2)을 살펴보자. 먼저 $v_2$는 $v_1$에서 가장 가까운(min = 1) 정점이므로 추가가 되고 (vnear = 2), 추후에 다시 고려할 필요가 없기 때문에 distance[vnear = 2]의 값을 -1로 할당한다. $v_2$를 추가함으로써 $v_4$까지 갈 수 있는 이음선이 생기며, 이 값은 6으로 초기값인 ∞보다 작으므로 distance[4], nearest[4]의 값을 갱신한다. 이 과정을 n-1번 반복하게 되며, 그 결과로 최소신장트리를 얻을 수 있다.
Pseudo Code
void prim(int n, const number W[ ][ ], set_of_edges& F) |
Source Code
// File: prim.h |
// File: prim.cpp |
|
Time Complexity Analysis
Basic operation
- There are two loops, each with n-1 iterations, inside the repeat loop. Executing the instructions inside each of them can be considered to be doing the basic operation once.
Input size
- n, the number of vertices.
Every-Case Time Complexity
- $T(n) = 2(n-1)(n-1) \in \Theta (n^2)$
Optimality Proof
Although greedy algorithms are often easier to develop than dynamic programming algorithms, usually it is more difficult to determine whether or not a greedy algorithm always produces an optimal solution
. Recall that for a dynamic programming algorithm we need only show that the principle of optimality applies. For a greedy algorithm we usually need a formal proof. Next we give such a proof for Prim’s algorithm.
프림 알고리즘이 찾아낸 신장트리가 최소신장트리인지 검증해야 한다. 다시 말하자면, 동 알고리즘을 통해 얻은 해답이 최적(optimal)인지를 결정해야 한다. 증명을 위해 보조 정리(Lemma)가 참임을 보이고 이를 이용하여 귀납법으로 프림 알고리즘이 최적의 원칙을 준수하는지 증명한다.
Lemma
Lemma
Let G = (V, E) be a connected, weight, undirected graph; let F be a promising subset of E; and let Y be the set of vertices connected by the edges in F. If e is an edge of minimum weight that connects a vertex in Y to a vertex in V - Y, then F U {e} is promising.
G = (V, E)는 연결되고, 가중치가 있는 비방향성 그래프라고 하자. F는 E의 유망한 부분집합이라 하자. Y는 F의 이음선들에 의해 연결된 정점들의 집합이라 하자. 이때 Y에 있는 정점과 V - Y에 있는 정점을 잇는 이음선 중, 그 가중치가 가장 작은 이음선을 e라고 하면, F U {e}는 유망하다.
유망하다는 말은, 비방향성 그래프 G = (V, E)가 주어지고 만약 E의 부분집합인 F에 최소신장트리가 되도록 이음선을 추가할 수 있으면 F는 유망하다(promising)라고 한다.
Proof
Because F is promising, there must be some set of edges F’ such that F ⊆ F’ and (V, F’) is a minimum spanning tree.
F가 유망하기 때문에(F에 최소신장트리가 되도록 이음선 추가 가능), F ⊆ F’ 이면서 (V, F’)가 최소신장트리가 되는 이음선의 집합 F’가 반드시 존재한다.
- If e ∈ F’, then F U {e} ⊆ F’, which means F U {e} is promising.
만일 e ∈ F’라면, F U {e} ⊆ F’가 되고, 따라서 F U {e}도 유망하다.
- Otherwise, because (V, F’) is a spanning tree, F’ U {e} must contain exactly one simple cycle and e must be in the cycle. There must be another edge e’ ∈ F’ in the simple cycle that also connects a vertex in Y to one in V - Y. If we remove e’ from F’ U {e}, the simple cycle disappears, which means that we have a spanning tree. Because e is an edge of minimum weight that connects a vertex in Y to on in V - Y, the weight of e must be less than or equal to the weight of e’ (in fact, they must be equal.) So F’ U {e} - {e’} is a minimum spanning tree. Now F U {e} ⊆ F’ U {e} - {e’}, because e’ cannot be in F (recall that edges in F cannot only vertices in Y.) Therefore, F U {e} is promising.
만일 e ∉ F’ 라면, (V, F’)는 이미 신장트리라는 뜻이다. 따라서 F’ U {e}는 정확히 하나의 단순순환경로를 포함해야하고 e는 그 순환경로 내에 있어야 한다. (위의 예제에서는 $v_1$ $\rightarrow$ $v_2$ $\rightarrow$ $v_4$ $\rightarrow$ $v_3$ $\rightarrow$ $v_1$)
Y에 있는 한 정점에서 V - Y에 있는 한 정점을 연결하는 임의의 이음선 e’ ⊆ F’는 그 순환경로 안에 반드시 존재하게 된다.
F’ U {e}에서 e’를 제거하면 단순순환경로는 사라지며 다시 신장트리가 형성된다. e는 Y에 있는 한 정점에서 V - Y에 있는 한 정점을 연결하는 최소가중치 이음선이므로, e의 가중치는 반드시 e’의 가중치 보다 작거나 같다. (실제로 반드시 같게 된다.) 그러면 F’ U {e} - {e’}는 최소신장트리이다.
결론적으로 e’가 F안에 있을 수 없으므로(F안에 있는 이음선들은 Y안에 있는 정점들 만을 연결함을 기억하라) F U {e} ⊆ F’ U {e} - {e’}가 되고, 따라서 F U {e}는 유망하다.
Theorem: Prim’s algorithm always produces a minimum spanning tree.
Proof
We use induction to show that the set F is promising after each iteration of the repeat loop.Induction base
Clearly the empty set is promising.Induction hypothesis
Assume that, after a given iteration of the repeat loop, the set of edges so far selected - namely, F is promising.Induction step
We need to show that the set F U {e} is promising, where e is the edge selected in the next iteration. Because the edge e selected in the next iteration is an edge of minimum weight that connects a vertex in Y to one on V - Y, F U {e} is promising, by Lemma. This completes the induction proof.
매번 반복이 수행된 후 E의 부분집합 F에 최소신장트리가 되도록 이음선을 추가할 수 있다는 것을 보이면 된다. (즉, F는 유망하다는 것을 입증한다.)
처음 시작은 공집합이다. 연결되고, 가중치가 있는 비방향성 그래프에서는 항상 최소신장트리가 존재하므로, 공집합 F를 포함하는 최소신장트리가 존재한다. 따라서 공집합이 아닌 F에 대해 F U {e}가 유망하다는 사실만 보이면 된다.
e는 다음 반복에서 선택된 이음선이다. e는 Y에 있는 정점을 V - Y에 있는 정점으로 연결하는 최소가중치를 지닌 이음선이기 때문에, 보조정리에 따라 F U {e}는 유망하다고 할 수 있다. 이것으로 귀납 증명이 완료된다.